using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Drawing;
using System.IO;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Drawing.Imaging;

namespace Intuipic.Interop
{
	public static class IconHelper
	{
		public static ImageSource GetSpecialFolderIcon(Environment.SpecialFolder specialFolder)
		{
			IntPtr pidl;
			SHGetSpecialFolderLocation(IntPtr.Zero, (int) specialFolder, out pidl);

			SHFILEINFO fileInfo = new SHFILEINFO();
			uint fileInfoSize = (uint) Marshal.SizeOf(fileInfo.GetType());
			FileInfoFlags flags = FileInfoFlags.SmallIcon | FileInfoFlags.Pidl | FileInfoFlags.Icon;

			if (SHGetFileInfoA(pidl, (uint) FileInfoAttributes.System, ref fileInfo, fileInfoSize, (uint) flags) == 0)
			{
				throw new InvalidOperationException();
			}

			return GetIconFromSHFILEINFO(fileInfo);
		}

		public static ImageSource GetIcon(string filename, FileInfoAttributes fileAttributes, FileInfoFlags flags)
		{
			SHFILEINFO fileInfo = new SHFILEINFO();
			uint fileInfoSize = (uint) Marshal.SizeOf(fileInfo.GetType());

			if (SHGetFileInfo(filename, (uint) fileAttributes, ref fileInfo, fileInfoSize, (uint) flags) == 0)
			{
				throw new InvalidOperationException();
			}

			return GetIconFromSHFILEINFO(fileInfo);
		}

		private static ImageSource GetIconFromSHFILEINFO(SHFILEINFO fileInfo)
		{
			Icon icon = Icon.FromHandle(fileInfo.hIcon).Clone() as Icon;
			Debug.Assert(icon != null);
			DestroyIcon(fileInfo.hIcon);

			using (MemoryStream memoryStream = new MemoryStream())
			using (Bitmap bitmap = icon.ToBitmap())
			{
				bitmap.Save(memoryStream, ImageFormat.Png);
				return BitmapFrame.Create(memoryStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
			}
		}

		[DllImport("shell32.dll")]
		private static extern long SHGetFileInfo(string path, uint attributes, ref SHFILEINFO b, uint fileInfo, uint flags);

		[DllImport("shell32.dll", CharSet = CharSet.Auto)]
		private static extern int SHGetFileInfoA(IntPtr Pidl, uint attributes, ref SHFILEINFO b, uint fileInfo, uint flags);

		[DllImport("shell32.dll", CharSet = CharSet.Auto)]
		private static extern uint SHGetSpecialFolderLocation(IntPtr hWnd, int nFolder, out IntPtr Pidl);

		[DllImport("user32.dll")]
		private static extern int DestroyIcon(IntPtr hIcon);

		// Nested Types
		[StructLayout(LayoutKind.Sequential)]
		private struct SHFILEINFO
		{
			public IntPtr hIcon;
			public int iIcon;
			public int dwAttributes;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
			public string szDisplayName;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
			public string szTypeName;
		}
	}
}
